import { ArcRotateCamera, BackgroundMaterial, Color3, Color4, CubeTexture, DirectionalLight, Engine, HemisphericLight, Mesh, MeshBuilder, Scene, ShadowGenerator, StandardMaterial, Texture, Texture, Vector3 } from "@babylonjs/core";

//环境纹理
export default class SkyBox {

    public engine: Engine;
    public scene: Scene;
    public canvas: HTMLCanvasElement;

    private updateAction: Map<number, (time: number) => {}> = new Map();
    private updateActionId: number = 0;

    public static skyBox: SkyBox;

    public constructor(canvas: HTMLCanvasElement) {
        this.canvas = canvas;
        this.engine = new Engine(canvas, true);
        this.scene = this.createScene();

        this.init();

        SkyBox.skyBox = this;
    }

    private init() {
        this.update(0);
    }

    private createScene() {
        const { engine, canvas } = this;
        let scene = new Scene(engine);
        scene.clearColor = new Color4(0, 0, 0, 1);

        const camera = new ArcRotateCamera('Camera', -Math.PI / 2, Math.PI / 3, 10, new Vector3(0, 0, 0), scene);
        camera.attachControl(canvas, true);

        // const texture = new Texture('https://playground.babylonjs.com/textures/grass.jpg');
        // texture.uScale = 5;
        // texture.vScale = 5;

        //背景材质 不需要灯光也会显示
        const mat = new BackgroundMaterial('backMat');
        // mat.diffuseTexture = texture;

        //设置为只接收阴影
        mat.shadowOnly = true;
        mat.primaryColor = new Color3(0, 0, 0);
        mat.alpha = 1;

        //用来接收阴影的地面
        const ground = MeshBuilder.CreateGround('ground', { width: 5, height: 5, subdivisions: 2 })
        ground.material = mat;
        ground.receiveShadows = true;//开启接受阴影


        //额外添加一层草地
        const mat1 = new BackgroundMaterial('backMat');
        mat1.diffuseTexture = new Texture('https://playground.babylonjs.com/textures/grass.jpg');
        const ground1 = MeshBuilder.CreateGround('ground', { width: 5, height: 5, subdivisions: 2 })
        ground1.material = mat1;


        const dir = new DirectionalLight('dir', new Vector3(-1, -3, -1), scene)
        const sphere = MeshBuilder.CreateSphere('sphere');
        sphere.position.y = 0.5;

        //添加阴影
        const shadowGen = new ShadowGenerator(512, dir);
        shadowGen.addShadowCaster(sphere);
        // mat.shadowLevel = 0.2;//阴影的透明度?(开启只接收阴影后无效)

        //阴影模糊
        shadowGen.useBlurExponentialShadowMap = true;
        shadowGen.useKernelBlur = true;
        shadowGen.blurKernel = 8;
        shadowGen.blurScale = 5;
        shadowGen.depthScale = 0;//???

        return scene;
    }

    private update(time: number) {
        const { updateAction, scene } = this;
        updateAction.forEach((action, key) => {
            action(time);
        });
        scene.render();
        requestAnimationFrame((time) => {
            this.update(time);
        });
    }

    public setUpdateAction(action: (time: number) => {}, id: number = -1) {
        const { updateAction } = this;
        let curId = id;
        if (id == -1) {
            curId = this.updateActionId++;
        } else if (id >= this.updateActionId) {
            curId = this.updateActionId++;
        }
        updateAction.set(curId, action);
    }
}